{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "de53995b-32ed-4722-8cac-ba104c8efacb",
   "metadata": {},
   "source": [
    "# 导入环境"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "52fac949-4150-4091-b0c3-2968ab5e385c",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from datasets import Dataset\n",
    "import pandas as pd\n",
    "from transformers import AutoTokenizer, AutoModelForCausalLM, DataCollatorForSeq2Seq, TrainingArguments, Trainer, GenerationConfig"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "e098d9eb",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# 读取json数据集文件\n",
    "df = pd.read_json('../../dataset/huanhuan.json')\n",
    "ds = Dataset.from_pandas(df)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "8ac92d42-efae-49b1-a00e-ccaa75b98938",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'instruction': ['小姐，别的秀女都在求中选，唯有咱们小姐想被撂牌子，菩萨一定记得真真儿的——',\n",
       "  '这个温太医啊，也是古怪，谁不知太医不得皇命不能为皇族以外的人请脉诊病，他倒好，十天半月便往咱们府里跑。',\n",
       "  '嬛妹妹，刚刚我去府上请脉，听甄伯母说你来这里进香了。'],\n",
       " 'input': ['', '', ''],\n",
       " 'output': ['嘘——都说许愿说破是不灵的。', '你们俩话太多了，我该和温太医要一剂药，好好治治你们。', '出来走走，也是散心。']}"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ds[:3] # 展示前三组数据"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "51d05e5d-d14e-4f03-92be-9a9677d41918",
   "metadata": {},
   "source": [
    "# 处理数据集"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "74ee5a67-2e55-4974-b90e-cbf492de500a",
   "metadata": {
    "scrolled": true,
    "tags": []
   },
   "outputs": [],
   "source": [
    "model_path = '/root/autodl-tmp/Shanghai_AI_Laboratory/internlm3-8b-instruct'\n",
    "\n",
    "tokenizer = AutoTokenizer.from_pretrained(model_path, use_fast=False, trust_remote_code=True)\n",
    "\n",
    "# 设置tokenizer.pad_token_id 和 tokenizer.eos_token_id,用于token填充和结束符\n",
    "# 在internlm3-8b-instruct/tokenizer_config.json中, 128131 是 '<|im_end|>' token值\n",
    "tokenizer.pad_token_id = tokenizer.eos_token_id = 128131  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "30288686-d58c-42d4-906a-122d324a7d86",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<s><|im_start|>system\n",
      "You are a helpful assistant.<|im_end|>\n",
      "<|im_start|>user\n",
      "你好呀<|im_end|>\n",
      "<|im_start|>assistant\n",
      "有什么可以帮你的？<|im_end|>\n",
      "<|im_start|>assistant\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# 使用tokenizer构建messages并打印， 查看chat_template的输出格式\n",
    "messages = [\n",
    "            {\"role\": \"system\", \"content\": \"You are a helpful assistant.\"},\n",
    "            {\"role\": \"user\", \"content\": '你好呀'},\n",
    "            {\"role\": \"assistant\", \"content\": '有什么可以帮你的？'}\n",
    "            ]\n",
    "# 使用chat_template将messages格式化并打印\n",
    "print(tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "2503a5fa-9621-4495-9035-8e7ef6525691",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "system_prompt = '现在你要扮演皇帝身边的女人--甄嬛'\n",
    "\n",
    "def process_func(example):\n",
    "    MAX_LENGTH = 384    # Llama分词器会将一个中文字切分为多个token，因此需要放开一些最大长度，保证数据的完整性\n",
    "    input_ids, attention_mask, labels = [], [], []\n",
    "    # 构建指令部分的输入, 可参考上面的输出格式进行调整和补充\n",
    "    instruction = tokenizer(\n",
    "        f\"<s><|im_start|>system\\n{system_prompt}<|im_end|>\\n\" \n",
    "        f\"<|im_start|>user\\n{example['instruction'] + example['input']}<|im_end|>\\n\"  \n",
    "        f\"<|im_start|>assistant\\n\",  \n",
    "        add_special_tokens=False   \n",
    "    )\n",
    "    # 构建模型回复部分的输入\n",
    "    response = tokenizer(\n",
    "        f\"{example['output']}\",\n",
    "        add_special_tokens=False \n",
    "    )\n",
    "    # 拼接指令和回复部分的 input_ids\n",
    "    input_ids = instruction[\"input_ids\"] + response[\"input_ids\"] + [tokenizer.pad_token_id]\n",
    "    # 拼接指令和回复部分的 attention_mask\n",
    "    attention_mask = instruction[\"attention_mask\"] + response[\"attention_mask\"] + [1]  # 因为 EOS token 也需要关注，所以补充为 1\n",
    "    # 构建标签\n",
    "    # 对于指令部分，使用 -100 忽略其损失计算；对于回复部分，保留其 input_ids 作为标签\n",
    "    labels = [-100] * len(instruction[\"input_ids\"]) + response[\"input_ids\"] + [tokenizer.pad_token_id]  \n",
    "    # 如果总长度超过最大长度，进行截断\n",
    "    if len(input_ids) > MAX_LENGTH: \n",
    "        input_ids = input_ids[:MAX_LENGTH]\n",
    "        attention_mask = attention_mask[:MAX_LENGTH]\n",
    "        labels = labels[:MAX_LENGTH]\n",
    "    return {\n",
    "        \"input_ids\": input_ids,\n",
    "        \"attention_mask\": attention_mask,\n",
    "        \"labels\": labels\n",
    "    }"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "84f870d6-73a9-4b0f-8abf-687b32224ad8",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "e3f9634fbaa74c38827c36f3d37d46e8",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Map:   0%|          | 0/3729 [00:00<?, ? examples/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "Dataset({\n",
       "    features: ['input_ids', 'attention_mask', 'labels'],\n",
       "    num_rows: 3729\n",
       "})"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tokenized_id = ds.map(process_func, remove_columns=ds.column_names)\n",
    "tokenized_id"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "1f7e15a0-4d9a-4935-9861-00cc472654b1",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<s><|im_start|>system\n",
      "现在你要扮演皇帝身边的女人--甄嬛<|im_end|>\n",
      "<|im_start|>user\n",
      "这个温太医啊，也是古怪，谁不知太医不得皇命不能为皇族以外的人请脉诊病，他倒好，十天半月便往咱们府里跑。<|im_end|>\n",
      "<|im_start|>assistant\n",
      "你们俩话太多了，我该和温太医要一剂药，好好治治你们。<|im_end|>\n"
     ]
    }
   ],
   "source": [
    "# 解码输入\n",
    "print(tokenizer.decode(tokenized_id[1]['input_ids']))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "97f16f66-324a-454f-8cc3-ef23b100ecff",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "你们俩话太多了，我该和温太医要一剂药，好好治治你们。<|im_end|>\n"
     ]
    }
   ],
   "source": [
    "# 解码标签, 过滤掉-100\n",
    "print(tokenizer.decode(list(filter(lambda x: x != -100, tokenized_id[1][\"labels\"]))))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "424823a8-ed0d-4309-83c8-3f6b1cdf274c",
   "metadata": {},
   "source": [
    "# 创建模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "170764e5-d899-4ef4-8c53-36f6dec0d198",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "20d392365e3e49e09319847f3d5280a3",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Loading checkpoint shards:   0%|          | 0/2 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "InternLM3ForCausalLM(\n",
       "  (model): InternLM3Model(\n",
       "    (embed_tokens): Embedding(128512, 4096, padding_idx=2)\n",
       "    (layers): ModuleList(\n",
       "      (0-47): 48 x InternLM3DecoderLayer(\n",
       "        (self_attn): InternLM3SdpaAttention(\n",
       "          (q_proj): Linear(in_features=4096, out_features=4096, bias=False)\n",
       "          (k_proj): Linear(in_features=4096, out_features=256, bias=False)\n",
       "          (v_proj): Linear(in_features=4096, out_features=256, bias=False)\n",
       "          (o_proj): Linear(in_features=4096, out_features=4096, bias=False)\n",
       "          (rotary_emb): InternLM3RotaryEmbedding()\n",
       "        )\n",
       "        (mlp): InternLM3MLP(\n",
       "          (gate_proj): Linear(in_features=4096, out_features=10240, bias=False)\n",
       "          (up_proj): Linear(in_features=4096, out_features=10240, bias=False)\n",
       "          (down_proj): Linear(in_features=10240, out_features=4096, bias=False)\n",
       "          (act_fn): SiLU()\n",
       "        )\n",
       "        (input_layernorm): InternLM3RMSNorm((4096,), eps=1e-05)\n",
       "        (post_attention_layernorm): InternLM3RMSNorm((4096,), eps=1e-05)\n",
       "      )\n",
       "    )\n",
       "    (norm): InternLM3RMSNorm((4096,), eps=1e-05)\n",
       "    (rotary_emb): InternLM3RotaryEmbedding()\n",
       "  )\n",
       "  (lm_head): Linear(in_features=4096, out_features=128512, bias=False)\n",
       ")"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import torch\n",
    "\n",
    "model = AutoModelForCausalLM.from_pretrained(model_path, device_map=\"auto\",\n",
    "                                             torch_dtype=torch.bfloat16, \n",
    "                                             trust_remote_code=True)\n",
    "model"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "352bc0a3",
   "metadata": {},
   "source": [
    "上面打印了 `InternLM3Model` 的模型结构， 可以看到里面的 `self_attn` 和 `mlp` 是两个主要的模块， 因此可以考虑将这两个模块作为 **LoRA** 微调 的  `target_modules` , 包括 `q_proj`, `k_proj`, `v_proj`, `o_proj` 以及 `gate_proj`、`up_proj` 和 `down_proj` 。\n",
    "\n",
    "通常我们只对 `self_attn` 模块中的 `q_proj`, `k_proj`, `v_proj`, `o_proj`进行微调， 本教程里我们也将对这四个模块进行微调演示， 感兴趣的同学可以自行尝试添加对 `mlp` 中的三个 `proj` 模块进行微调。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "2323eac7-37d5-4288-8bc5-79fac7113402",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "model.enable_input_require_grads() # 开启梯度检查点时，要执行该方法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "f808b05c-f2cb-48cf-a80d-0c42be6051c7",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.bfloat16"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "model.dtype"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "13d71257-3c1c-4303-8ff8-af161ebc2cf1",
   "metadata": {},
   "source": [
    "# LoRA "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "2d304ae2-ab60-4080-a80d-19cac2e3ade3",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from peft import LoraConfig, TaskType, get_peft_model\n",
    "\n",
    "config = LoraConfig(\n",
    "    task_type=TaskType.CAUSAL_LM, \n",
    "    target_modules=[\"q_proj\", \"k_proj\",\"v_proj\", \"o_proj\"], # 可以自行添加更多微调的target_modules\n",
    "    inference_mode=False, # 训练模式\n",
    "    r=8,                  # Lora 秩\n",
    "    lora_alpha=32,        # Lora alaph，具体作用参见 Lora 原理\n",
    "    lora_dropout=0.1      # Dropout 比例\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "2c2489c5-eaab-4e1f-b06a-c3f914b4bf8e",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "PeftModelForCausalLM(\n",
       "  (base_model): LoraModel(\n",
       "    (model): PeftModelForCausalLM(\n",
       "      (base_model): LoraModel(\n",
       "        (model): InternLM3ForCausalLM(\n",
       "          (model): InternLM3Model(\n",
       "            (embed_tokens): Embedding(128512, 4096, padding_idx=2)\n",
       "            (layers): ModuleList(\n",
       "              (0-47): 48 x InternLM3DecoderLayer(\n",
       "                (self_attn): InternLM3SdpaAttention(\n",
       "                  (q_proj): lora.Linear(\n",
       "                    (base_layer): Linear(in_features=4096, out_features=4096, bias=False)\n",
       "                    (lora_dropout): ModuleDict(\n",
       "                      (default): Dropout(p=0.1, inplace=False)\n",
       "                    )\n",
       "                    (lora_A): ModuleDict(\n",
       "                      (default): Linear(in_features=4096, out_features=8, bias=False)\n",
       "                    )\n",
       "                    (lora_B): ModuleDict(\n",
       "                      (default): Linear(in_features=8, out_features=4096, bias=False)\n",
       "                    )\n",
       "                    (lora_embedding_A): ParameterDict()\n",
       "                    (lora_embedding_B): ParameterDict()\n",
       "                  )\n",
       "                  (k_proj): lora.Linear(\n",
       "                    (base_layer): Linear(in_features=4096, out_features=256, bias=False)\n",
       "                    (lora_dropout): ModuleDict(\n",
       "                      (default): Dropout(p=0.1, inplace=False)\n",
       "                    )\n",
       "                    (lora_A): ModuleDict(\n",
       "                      (default): Linear(in_features=4096, out_features=8, bias=False)\n",
       "                    )\n",
       "                    (lora_B): ModuleDict(\n",
       "                      (default): Linear(in_features=8, out_features=256, bias=False)\n",
       "                    )\n",
       "                    (lora_embedding_A): ParameterDict()\n",
       "                    (lora_embedding_B): ParameterDict()\n",
       "                  )\n",
       "                  (v_proj): lora.Linear(\n",
       "                    (base_layer): Linear(in_features=4096, out_features=256, bias=False)\n",
       "                    (lora_dropout): ModuleDict(\n",
       "                      (default): Dropout(p=0.1, inplace=False)\n",
       "                    )\n",
       "                    (lora_A): ModuleDict(\n",
       "                      (default): Linear(in_features=4096, out_features=8, bias=False)\n",
       "                    )\n",
       "                    (lora_B): ModuleDict(\n",
       "                      (default): Linear(in_features=8, out_features=256, bias=False)\n",
       "                    )\n",
       "                    (lora_embedding_A): ParameterDict()\n",
       "                    (lora_embedding_B): ParameterDict()\n",
       "                  )\n",
       "                  (o_proj): lora.Linear(\n",
       "                    (base_layer): Linear(in_features=4096, out_features=4096, bias=False)\n",
       "                    (lora_dropout): ModuleDict(\n",
       "                      (default): Dropout(p=0.1, inplace=False)\n",
       "                    )\n",
       "                    (lora_A): ModuleDict(\n",
       "                      (default): Linear(in_features=4096, out_features=8, bias=False)\n",
       "                    )\n",
       "                    (lora_B): ModuleDict(\n",
       "                      (default): Linear(in_features=8, out_features=4096, bias=False)\n",
       "                    )\n",
       "                    (lora_embedding_A): ParameterDict()\n",
       "                    (lora_embedding_B): ParameterDict()\n",
       "                  )\n",
       "                  (rotary_emb): InternLM3RotaryEmbedding()\n",
       "                )\n",
       "                (mlp): InternLM3MLP(\n",
       "                  (gate_proj): Linear(in_features=4096, out_features=10240, bias=False)\n",
       "                  (up_proj): Linear(in_features=4096, out_features=10240, bias=False)\n",
       "                  (down_proj): Linear(in_features=10240, out_features=4096, bias=False)\n",
       "                  (act_fn): SiLU()\n",
       "                )\n",
       "                (input_layernorm): InternLM3RMSNorm((4096,), eps=1e-05)\n",
       "                (post_attention_layernorm): InternLM3RMSNorm((4096,), eps=1e-05)\n",
       "              )\n",
       "            )\n",
       "            (norm): InternLM3RMSNorm((4096,), eps=1e-05)\n",
       "            (rotary_emb): InternLM3RotaryEmbedding()\n",
       "          )\n",
       "          (lm_head): Linear(in_features=4096, out_features=128512, bias=False)\n",
       "        )\n",
       "      )\n",
       "    )\n",
       "  )\n",
       ")"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "model = get_peft_model(model, config)\n",
    "model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "ebf5482b-fab9-4eb3-ad88-c116def4be12",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "trainable params: 9,633,792 || all params: 8,813,875,200 || trainable%: 0.1093\n"
     ]
    }
   ],
   "source": [
    "model.print_trainable_parameters()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ca055683-837f-4865-9c57-9164ba60c00f",
   "metadata": {},
   "source": [
    "# 配置训练参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "7e76bbff-15fd-4995-a61d-8364dc5e9ea0",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# # 屏蔽令人讨厌的保存模型权重时UserWarning（Could not find a config file in model_path will assume that the vocabulary was not modified.）\n",
    "# 建议训练时打开\n",
    "# import warnings\n",
    "# warnings.filterwarnings(\"ignore\") \n",
    "\n",
    "output_dir=\"/root/autodl-tmp/internlm3-8b-instruct_lora_output\"\n",
    "\n",
    "args = TrainingArguments(\n",
    "    output_dir=output_dir,\n",
    "    per_device_train_batch_size=1,\n",
    "    gradient_accumulation_steps=4,\n",
    "    logging_steps=10,\n",
    "    num_train_epochs=3,\n",
    "    save_steps=100, \n",
    "    learning_rate=1e-4,\n",
    "    save_on_each_node=True,\n",
    "    gradient_checkpointing=True  # 开启梯度检查点，可以节省显存，加快训练速度，但会消耗更多内存， 对应model.enable_input_require_grads() \n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "f142cb9c-ad99-48e6-ba86-6df198f9ed96",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "trainer = Trainer(\n",
    "    model=model,\n",
    "    args=args,\n",
    "    train_dataset=tokenized_id,\n",
    "    data_collator=DataCollatorForSeq2Seq(tokenizer=tokenizer, padding=True),\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "aec9bc36-b297-45af-99e1-d4c4d82be081",
   "metadata": {
    "scrolled": true,
    "tags": []
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "`use_cache=True` is incompatible with gradient checkpointing. Setting `use_cache=False`.\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "\n",
       "    <div>\n",
       "      \n",
       "      <progress value='2796' max='2796' style='width:300px; height:20px; vertical-align: middle;'></progress>\n",
       "      [2796/2796 35:50, Epoch 2/3]\n",
       "    </div>\n",
       "    <table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       " <tr style=\"text-align: left;\">\n",
       "      <th>Step</th>\n",
       "      <th>Training Loss</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <td>10</td>\n",
       "      <td>3.057100</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>20</td>\n",
       "      <td>2.831100</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>30</td>\n",
       "      <td>2.496800</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>40</td>\n",
       "      <td>2.893900</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>50</td>\n",
       "      <td>2.527500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>60</td>\n",
       "      <td>2.542800</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>70</td>\n",
       "      <td>2.628200</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>80</td>\n",
       "      <td>2.705100</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>90</td>\n",
       "      <td>2.512800</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>100</td>\n",
       "      <td>2.677600</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>110</td>\n",
       "      <td>2.752500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>120</td>\n",
       "      <td>2.688500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>130</td>\n",
       "      <td>2.559200</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>140</td>\n",
       "      <td>2.548800</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>150</td>\n",
       "      <td>2.394900</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>160</td>\n",
       "      <td>2.562000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>170</td>\n",
       "      <td>2.522100</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>180</td>\n",
       "      <td>2.533100</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>190</td>\n",
       "      <td>2.651200</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>200</td>\n",
       "      <td>2.478600</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>210</td>\n",
       "      <td>2.583700</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>220</td>\n",
       "      <td>2.524700</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>230</td>\n",
       "      <td>2.515500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>240</td>\n",
       "      <td>2.496000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>250</td>\n",
       "      <td>2.685400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>260</td>\n",
       "      <td>2.433600</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>270</td>\n",
       "      <td>2.574400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>280</td>\n",
       "      <td>2.459500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>290</td>\n",
       "      <td>2.624800</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>300</td>\n",
       "      <td>2.661200</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>310</td>\n",
       "      <td>2.763900</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>320</td>\n",
       "      <td>2.585700</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>330</td>\n",
       "      <td>2.375300</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>340</td>\n",
       "      <td>2.669200</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>350</td>\n",
       "      <td>2.629300</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>360</td>\n",
       "      <td>2.707800</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>370</td>\n",
       "      <td>2.478400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>380</td>\n",
       "      <td>2.436400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>390</td>\n",
       "      <td>2.616100</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>400</td>\n",
       "      <td>2.633100</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>410</td>\n",
       "      <td>2.319400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>420</td>\n",
       "      <td>2.717900</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>430</td>\n",
       "      <td>2.594800</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>440</td>\n",
       "      <td>2.525200</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>450</td>\n",
       "      <td>2.584100</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>460</td>\n",
       "      <td>2.630700</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>470</td>\n",
       "      <td>2.456800</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>480</td>\n",
       "      <td>2.613700</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>490</td>\n",
       "      <td>2.534900</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>500</td>\n",
       "      <td>2.414900</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>510</td>\n",
       "      <td>2.647900</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>520</td>\n",
       "      <td>2.639100</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>530</td>\n",
       "      <td>2.607500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>540</td>\n",
       "      <td>2.296600</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>550</td>\n",
       "      <td>2.413500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>560</td>\n",
       "      <td>2.687400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>570</td>\n",
       "      <td>2.745900</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>580</td>\n",
       "      <td>2.507300</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>590</td>\n",
       "      <td>2.629100</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>600</td>\n",
       "      <td>2.651600</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>610</td>\n",
       "      <td>2.795600</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>620</td>\n",
       "      <td>2.624100</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>630</td>\n",
       "      <td>2.316400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>640</td>\n",
       "      <td>2.649300</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>650</td>\n",
       "      <td>2.562600</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>660</td>\n",
       "      <td>2.698900</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>670</td>\n",
       "      <td>2.594700</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>680</td>\n",
       "      <td>2.401000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>690</td>\n",
       "      <td>2.481600</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>700</td>\n",
       "      <td>2.346700</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>710</td>\n",
       "      <td>2.358000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>720</td>\n",
       "      <td>2.548300</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>730</td>\n",
       "      <td>2.542700</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>740</td>\n",
       "      <td>2.495400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>750</td>\n",
       "      <td>2.562600</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>760</td>\n",
       "      <td>2.375700</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>770</td>\n",
       "      <td>2.494300</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>780</td>\n",
       "      <td>2.636300</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>790</td>\n",
       "      <td>2.540100</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>800</td>\n",
       "      <td>2.429500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>810</td>\n",
       "      <td>2.875600</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>820</td>\n",
       "      <td>2.276200</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>830</td>\n",
       "      <td>2.493700</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>840</td>\n",
       "      <td>2.303400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>850</td>\n",
       "      <td>2.144500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>860</td>\n",
       "      <td>2.682300</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>870</td>\n",
       "      <td>2.474700</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>880</td>\n",
       "      <td>2.625000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>890</td>\n",
       "      <td>2.494600</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>900</td>\n",
       "      <td>2.523400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>910</td>\n",
       "      <td>2.614700</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>920</td>\n",
       "      <td>2.493700</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>930</td>\n",
       "      <td>2.645600</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>940</td>\n",
       "      <td>2.580300</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>950</td>\n",
       "      <td>2.445000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>960</td>\n",
       "      <td>2.342100</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>970</td>\n",
       "      <td>2.314900</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>980</td>\n",
       "      <td>2.408000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>990</td>\n",
       "      <td>2.493400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1000</td>\n",
       "      <td>2.434700</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1010</td>\n",
       "      <td>2.179500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1020</td>\n",
       "      <td>2.416800</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1030</td>\n",
       "      <td>2.296600</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1040</td>\n",
       "      <td>2.339000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1050</td>\n",
       "      <td>2.180400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1060</td>\n",
       "      <td>2.378200</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1070</td>\n",
       "      <td>2.297800</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1080</td>\n",
       "      <td>2.451300</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1090</td>\n",
       "      <td>2.449200</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1100</td>\n",
       "      <td>2.535500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1110</td>\n",
       "      <td>2.433400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1120</td>\n",
       "      <td>2.260800</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1130</td>\n",
       "      <td>2.595300</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1140</td>\n",
       "      <td>2.662100</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1150</td>\n",
       "      <td>2.544200</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1160</td>\n",
       "      <td>2.133100</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1170</td>\n",
       "      <td>2.359800</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1180</td>\n",
       "      <td>2.381400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1190</td>\n",
       "      <td>2.410800</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1200</td>\n",
       "      <td>2.487000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1210</td>\n",
       "      <td>2.463600</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1220</td>\n",
       "      <td>2.475500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1230</td>\n",
       "      <td>2.178400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1240</td>\n",
       "      <td>2.421400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1250</td>\n",
       "      <td>2.383300</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1260</td>\n",
       "      <td>2.209500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1270</td>\n",
       "      <td>2.628900</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1280</td>\n",
       "      <td>2.447500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1290</td>\n",
       "      <td>2.499400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1300</td>\n",
       "      <td>2.252000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1310</td>\n",
       "      <td>2.480000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1320</td>\n",
       "      <td>2.455900</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1330</td>\n",
       "      <td>2.609000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1340</td>\n",
       "      <td>2.234000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1350</td>\n",
       "      <td>2.373200</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1360</td>\n",
       "      <td>2.372200</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1370</td>\n",
       "      <td>2.410300</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1380</td>\n",
       "      <td>2.642800</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1390</td>\n",
       "      <td>2.488700</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1400</td>\n",
       "      <td>2.397000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1410</td>\n",
       "      <td>2.450900</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1420</td>\n",
       "      <td>2.348200</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1430</td>\n",
       "      <td>2.378200</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1440</td>\n",
       "      <td>2.490700</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1450</td>\n",
       "      <td>2.384000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1460</td>\n",
       "      <td>2.474700</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1470</td>\n",
       "      <td>2.447800</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1480</td>\n",
       "      <td>2.432800</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1490</td>\n",
       "      <td>2.462700</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1500</td>\n",
       "      <td>2.486200</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1510</td>\n",
       "      <td>2.429500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1520</td>\n",
       "      <td>2.247100</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1530</td>\n",
       "      <td>2.251400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1540</td>\n",
       "      <td>2.590200</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1550</td>\n",
       "      <td>2.563400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1560</td>\n",
       "      <td>2.426400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1570</td>\n",
       "      <td>2.347000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1580</td>\n",
       "      <td>2.412400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1590</td>\n",
       "      <td>2.150500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1600</td>\n",
       "      <td>2.457900</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1610</td>\n",
       "      <td>2.379400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1620</td>\n",
       "      <td>2.507800</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1630</td>\n",
       "      <td>2.452900</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1640</td>\n",
       "      <td>2.638100</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1650</td>\n",
       "      <td>2.333000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1660</td>\n",
       "      <td>2.495900</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1670</td>\n",
       "      <td>2.314400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1680</td>\n",
       "      <td>2.130600</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1690</td>\n",
       "      <td>2.506500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1700</td>\n",
       "      <td>2.533300</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1710</td>\n",
       "      <td>2.246600</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1720</td>\n",
       "      <td>2.323700</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1730</td>\n",
       "      <td>2.405400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1740</td>\n",
       "      <td>2.192200</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1750</td>\n",
       "      <td>2.376200</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1760</td>\n",
       "      <td>2.365900</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1770</td>\n",
       "      <td>2.377700</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1780</td>\n",
       "      <td>2.410600</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1790</td>\n",
       "      <td>2.394700</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1800</td>\n",
       "      <td>2.497400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1810</td>\n",
       "      <td>2.318400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1820</td>\n",
       "      <td>2.301100</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1830</td>\n",
       "      <td>2.411300</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1840</td>\n",
       "      <td>2.523900</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1850</td>\n",
       "      <td>2.498200</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1860</td>\n",
       "      <td>2.317000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1870</td>\n",
       "      <td>2.273200</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1880</td>\n",
       "      <td>2.170200</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1890</td>\n",
       "      <td>2.188700</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1900</td>\n",
       "      <td>2.285600</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1910</td>\n",
       "      <td>2.416900</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1920</td>\n",
       "      <td>2.245500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1930</td>\n",
       "      <td>2.102000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1940</td>\n",
       "      <td>2.347100</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1950</td>\n",
       "      <td>2.230000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1960</td>\n",
       "      <td>2.432100</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1970</td>\n",
       "      <td>2.234600</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1980</td>\n",
       "      <td>2.292900</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1990</td>\n",
       "      <td>2.273500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2000</td>\n",
       "      <td>2.329300</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2010</td>\n",
       "      <td>2.290900</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2020</td>\n",
       "      <td>2.222600</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2030</td>\n",
       "      <td>2.249600</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2040</td>\n",
       "      <td>2.324400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2050</td>\n",
       "      <td>2.338800</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2060</td>\n",
       "      <td>2.225500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2070</td>\n",
       "      <td>2.340300</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2080</td>\n",
       "      <td>2.099300</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2090</td>\n",
       "      <td>2.219300</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2100</td>\n",
       "      <td>2.272300</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2110</td>\n",
       "      <td>2.409400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2120</td>\n",
       "      <td>2.265000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2130</td>\n",
       "      <td>2.304100</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2140</td>\n",
       "      <td>2.367800</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2150</td>\n",
       "      <td>2.434300</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2160</td>\n",
       "      <td>2.372400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2170</td>\n",
       "      <td>2.476700</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2180</td>\n",
       "      <td>2.356300</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2190</td>\n",
       "      <td>2.282900</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2200</td>\n",
       "      <td>2.383300</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2210</td>\n",
       "      <td>2.446300</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2220</td>\n",
       "      <td>2.504400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2230</td>\n",
       "      <td>2.379300</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2240</td>\n",
       "      <td>2.362600</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2250</td>\n",
       "      <td>2.249000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2260</td>\n",
       "      <td>2.343500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2270</td>\n",
       "      <td>2.270800</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2280</td>\n",
       "      <td>2.422400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2290</td>\n",
       "      <td>2.297600</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2300</td>\n",
       "      <td>2.378500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2310</td>\n",
       "      <td>2.221000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2320</td>\n",
       "      <td>2.090000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2330</td>\n",
       "      <td>2.422100</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2340</td>\n",
       "      <td>2.195700</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2350</td>\n",
       "      <td>2.343700</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2360</td>\n",
       "      <td>2.308500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2370</td>\n",
       "      <td>2.149300</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2380</td>\n",
       "      <td>2.255500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2390</td>\n",
       "      <td>2.301500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2400</td>\n",
       "      <td>2.319500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2410</td>\n",
       "      <td>2.289100</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2420</td>\n",
       "      <td>2.438200</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2430</td>\n",
       "      <td>2.510100</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2440</td>\n",
       "      <td>2.177800</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2450</td>\n",
       "      <td>2.234300</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2460</td>\n",
       "      <td>2.366000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2470</td>\n",
       "      <td>2.274400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2480</td>\n",
       "      <td>2.339600</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2490</td>\n",
       "      <td>2.338500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2500</td>\n",
       "      <td>2.475700</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2510</td>\n",
       "      <td>2.362600</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2520</td>\n",
       "      <td>2.283000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2530</td>\n",
       "      <td>2.148800</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2540</td>\n",
       "      <td>2.432400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2550</td>\n",
       "      <td>2.304600</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2560</td>\n",
       "      <td>2.506300</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2570</td>\n",
       "      <td>2.241700</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2580</td>\n",
       "      <td>2.379000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2590</td>\n",
       "      <td>2.331900</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2600</td>\n",
       "      <td>2.336400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2610</td>\n",
       "      <td>2.461600</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2620</td>\n",
       "      <td>2.521200</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2630</td>\n",
       "      <td>2.230800</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2640</td>\n",
       "      <td>2.466500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2650</td>\n",
       "      <td>2.538000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2660</td>\n",
       "      <td>2.540500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2670</td>\n",
       "      <td>2.465400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2680</td>\n",
       "      <td>2.084900</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2690</td>\n",
       "      <td>2.172600</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2700</td>\n",
       "      <td>2.262000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2710</td>\n",
       "      <td>2.301400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2720</td>\n",
       "      <td>2.228400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2730</td>\n",
       "      <td>2.285400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2740</td>\n",
       "      <td>2.431300</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2750</td>\n",
       "      <td>2.156300</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2760</td>\n",
       "      <td>2.271600</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2770</td>\n",
       "      <td>2.243900</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2780</td>\n",
       "      <td>2.116000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2790</td>\n",
       "      <td>2.380400</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table><p>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/root/miniconda3/lib/python3.12/site-packages/peft/utils/save_and_load.py:195: UserWarning: Could not find a config file in /root/autodl-tmp/Shanghai_AI_Laboratory/internlm3-8b-instruct - will assume that the vocabulary was not modified.\n",
      "  warnings.warn(\n",
      "/root/miniconda3/lib/python3.12/site-packages/peft/utils/save_and_load.py:195: UserWarning: Could not find a config file in /root/autodl-tmp/Shanghai_AI_Laboratory/internlm3-8b-instruct - will assume that the vocabulary was not modified.\n",
      "  warnings.warn(\n",
      "/root/miniconda3/lib/python3.12/site-packages/peft/utils/save_and_load.py:195: UserWarning: Could not find a config file in /root/autodl-tmp/Shanghai_AI_Laboratory/internlm3-8b-instruct - will assume that the vocabulary was not modified.\n",
      "  warnings.warn(\n",
      "/root/miniconda3/lib/python3.12/site-packages/peft/utils/save_and_load.py:195: UserWarning: Could not find a config file in /root/autodl-tmp/Shanghai_AI_Laboratory/internlm3-8b-instruct - will assume that the vocabulary was not modified.\n",
      "  warnings.warn(\n",
      "/root/miniconda3/lib/python3.12/site-packages/peft/utils/save_and_load.py:195: UserWarning: Could not find a config file in /root/autodl-tmp/Shanghai_AI_Laboratory/internlm3-8b-instruct - will assume that the vocabulary was not modified.\n",
      "  warnings.warn(\n",
      "/root/miniconda3/lib/python3.12/site-packages/peft/utils/save_and_load.py:195: UserWarning: Could not find a config file in /root/autodl-tmp/Shanghai_AI_Laboratory/internlm3-8b-instruct - will assume that the vocabulary was not modified.\n",
      "  warnings.warn(\n",
      "/root/miniconda3/lib/python3.12/site-packages/peft/utils/save_and_load.py:195: UserWarning: Could not find a config file in /root/autodl-tmp/Shanghai_AI_Laboratory/internlm3-8b-instruct - will assume that the vocabulary was not modified.\n",
      "  warnings.warn(\n",
      "/root/miniconda3/lib/python3.12/site-packages/peft/utils/save_and_load.py:195: UserWarning: Could not find a config file in /root/autodl-tmp/Shanghai_AI_Laboratory/internlm3-8b-instruct - will assume that the vocabulary was not modified.\n",
      "  warnings.warn(\n",
      "/root/miniconda3/lib/python3.12/site-packages/peft/utils/save_and_load.py:195: UserWarning: Could not find a config file in /root/autodl-tmp/Shanghai_AI_Laboratory/internlm3-8b-instruct - will assume that the vocabulary was not modified.\n",
      "  warnings.warn(\n",
      "/root/miniconda3/lib/python3.12/site-packages/peft/utils/save_and_load.py:195: UserWarning: Could not find a config file in /root/autodl-tmp/Shanghai_AI_Laboratory/internlm3-8b-instruct - will assume that the vocabulary was not modified.\n",
      "  warnings.warn(\n",
      "/root/miniconda3/lib/python3.12/site-packages/peft/utils/save_and_load.py:195: UserWarning: Could not find a config file in /root/autodl-tmp/Shanghai_AI_Laboratory/internlm3-8b-instruct - will assume that the vocabulary was not modified.\n",
      "  warnings.warn(\n",
      "/root/miniconda3/lib/python3.12/site-packages/peft/utils/save_and_load.py:195: UserWarning: Could not find a config file in /root/autodl-tmp/Shanghai_AI_Laboratory/internlm3-8b-instruct - will assume that the vocabulary was not modified.\n",
      "  warnings.warn(\n",
      "/root/miniconda3/lib/python3.12/site-packages/peft/utils/save_and_load.py:195: UserWarning: Could not find a config file in /root/autodl-tmp/Shanghai_AI_Laboratory/internlm3-8b-instruct - will assume that the vocabulary was not modified.\n",
      "  warnings.warn(\n",
      "/root/miniconda3/lib/python3.12/site-packages/peft/utils/save_and_load.py:195: UserWarning: Could not find a config file in /root/autodl-tmp/Shanghai_AI_Laboratory/internlm3-8b-instruct - will assume that the vocabulary was not modified.\n",
      "  warnings.warn(\n",
      "/root/miniconda3/lib/python3.12/site-packages/peft/utils/save_and_load.py:195: UserWarning: Could not find a config file in /root/autodl-tmp/Shanghai_AI_Laboratory/internlm3-8b-instruct - will assume that the vocabulary was not modified.\n",
      "  warnings.warn(\n",
      "/root/miniconda3/lib/python3.12/site-packages/peft/utils/save_and_load.py:195: UserWarning: Could not find a config file in /root/autodl-tmp/Shanghai_AI_Laboratory/internlm3-8b-instruct - will assume that the vocabulary was not modified.\n",
      "  warnings.warn(\n",
      "/root/miniconda3/lib/python3.12/site-packages/peft/utils/save_and_load.py:195: UserWarning: Could not find a config file in /root/autodl-tmp/Shanghai_AI_Laboratory/internlm3-8b-instruct - will assume that the vocabulary was not modified.\n",
      "  warnings.warn(\n",
      "/root/miniconda3/lib/python3.12/site-packages/peft/utils/save_and_load.py:195: UserWarning: Could not find a config file in /root/autodl-tmp/Shanghai_AI_Laboratory/internlm3-8b-instruct - will assume that the vocabulary was not modified.\n",
      "  warnings.warn(\n",
      "/root/miniconda3/lib/python3.12/site-packages/peft/utils/save_and_load.py:195: UserWarning: Could not find a config file in /root/autodl-tmp/Shanghai_AI_Laboratory/internlm3-8b-instruct - will assume that the vocabulary was not modified.\n",
      "  warnings.warn(\n",
      "/root/miniconda3/lib/python3.12/site-packages/peft/utils/save_and_load.py:195: UserWarning: Could not find a config file in /root/autodl-tmp/Shanghai_AI_Laboratory/internlm3-8b-instruct - will assume that the vocabulary was not modified.\n",
      "  warnings.warn(\n",
      "/root/miniconda3/lib/python3.12/site-packages/peft/utils/save_and_load.py:195: UserWarning: Could not find a config file in /root/autodl-tmp/Shanghai_AI_Laboratory/internlm3-8b-instruct - will assume that the vocabulary was not modified.\n",
      "  warnings.warn(\n",
      "/root/miniconda3/lib/python3.12/site-packages/peft/utils/save_and_load.py:195: UserWarning: Could not find a config file in /root/autodl-tmp/Shanghai_AI_Laboratory/internlm3-8b-instruct - will assume that the vocabulary was not modified.\n",
      "  warnings.warn(\n",
      "/root/miniconda3/lib/python3.12/site-packages/peft/utils/save_and_load.py:195: UserWarning: Could not find a config file in /root/autodl-tmp/Shanghai_AI_Laboratory/internlm3-8b-instruct - will assume that the vocabulary was not modified.\n",
      "  warnings.warn(\n",
      "/root/miniconda3/lib/python3.12/site-packages/peft/utils/save_and_load.py:195: UserWarning: Could not find a config file in /root/autodl-tmp/Shanghai_AI_Laboratory/internlm3-8b-instruct - will assume that the vocabulary was not modified.\n",
      "  warnings.warn(\n",
      "/root/miniconda3/lib/python3.12/site-packages/peft/utils/save_and_load.py:195: UserWarning: Could not find a config file in /root/autodl-tmp/Shanghai_AI_Laboratory/internlm3-8b-instruct - will assume that the vocabulary was not modified.\n",
      "  warnings.warn(\n",
      "/root/miniconda3/lib/python3.12/site-packages/peft/utils/save_and_load.py:195: UserWarning: Could not find a config file in /root/autodl-tmp/Shanghai_AI_Laboratory/internlm3-8b-instruct - will assume that the vocabulary was not modified.\n",
      "  warnings.warn(\n",
      "/root/miniconda3/lib/python3.12/site-packages/peft/utils/save_and_load.py:195: UserWarning: Could not find a config file in /root/autodl-tmp/Shanghai_AI_Laboratory/internlm3-8b-instruct - will assume that the vocabulary was not modified.\n",
      "  warnings.warn(\n",
      "/root/miniconda3/lib/python3.12/site-packages/peft/utils/save_and_load.py:195: UserWarning: Could not find a config file in /root/autodl-tmp/Shanghai_AI_Laboratory/internlm3-8b-instruct - will assume that the vocabulary was not modified.\n",
      "  warnings.warn(\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "TrainOutput(global_step=2796, training_loss=2.428081802032536, metrics={'train_runtime': 2152.3486, 'train_samples_per_second': 5.198, 'train_steps_per_second': 1.299, 'total_flos': 4.408379498714726e+16, 'train_loss': 2.428081802032536, 'epoch': 2.997586484312148})"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "trainer.train()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8abb2327-458e-4e96-ac98-2141b5b97c8e",
   "metadata": {},
   "source": [
    "# 合并加载模型\n",
    "\n",
    "> 这里推荐大家在**训练结束重启一下notebook, 释放微调占用的GPU显存**, 否则容易出现如下警告\"Some parameters are on the meta device because they were offloaded to the cpu.\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "bd2a415a-a9ad-49ea-877f-243558a83bfc",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "4f177d8f03bf4de8bfd9fba99946e991",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Loading checkpoint shards:   0%|          | 0/2 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "prompt:  你是谁？\n",
      "system_prompt:  现在你要扮演皇帝身边的女人--甄嬛\n",
      "output:  我是甄嬛，家父是大理寺少卿甄远道。\n"
     ]
    }
   ],
   "source": [
    "from transformers import AutoModelForCausalLM, AutoTokenizer\n",
    "import torch\n",
    "from peft import PeftModel\n",
    "\n",
    "model_path = '/root/autodl-tmp/Shanghai_AI_Laboratory/internlm3-8b-instruct'\n",
    "lora_path = '/root/autodl-tmp/internlm3-8b-instruct_lora_output/checkpoint-2796' # 这里改成 LoRA 输出对应 checkpoint 地址和最终的 epoch 数值 2796\n",
    "\n",
    "# 加载tokenizer\n",
    "tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)\n",
    "\n",
    "# 加载模型\n",
    "model = AutoModelForCausalLM.from_pretrained(model_path, \n",
    "                                             device_map=\"auto\",\n",
    "                                             torch_dtype=torch.bfloat16, \n",
    "                                             trust_remote_code=True).eval()\n",
    "\n",
    "# 加载lora权重\n",
    "model = PeftModel.from_pretrained(model, model_id=lora_path)\n",
    "\n",
    "prompt = \"你是谁？\"\n",
    "system_prompt = \"现在你要扮演皇帝身边的女人--甄嬛\"\n",
    "print(\"prompt: \", prompt)\n",
    "print(\"system_prompt: \", system_prompt)\n",
    "\n",
    "inputs = tokenizer.apply_chat_template([{\"role\": \"system\", \"content\": system_prompt},\n",
    "                                        {\"role\": \"user\", \"content\": prompt}],\n",
    "                                       add_generation_prompt=True,\n",
    "                                       tokenize=True,\n",
    "                                       return_tensors=\"pt\",\n",
    "                                       return_dict=True\n",
    "                                       ).to(model.device)  # 将 inputs 移动到模型所在的设备，确保设备一致性\n",
    "\n",
    "\n",
    "gen_kwargs = {\"max_length\": 2500, \"do_sample\": True, \"top_k\": 1}\n",
    "with torch.no_grad():\n",
    "    outputs = model.generate(**inputs, **gen_kwargs)\n",
    "    outputs = outputs[:, inputs['input_ids'].shape[1]:]\n",
    "    print(\"output: \", tokenizer.decode(outputs[0], skip_special_tokens=True))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
